require "AoE_Skillshot_Position"
require "DrawDamageLib"
class 'Plugin'

if myHero.charName ~= "Orianna" then return end

local version = "1.65"

local qRange = 825
local wRange = 240
local eRange = 1120
local rRange = 350
local qWidth = 80
local rWidth = 300
local ball = myHero
local Recalling = false
local ballMoving = false
local ballColor = 0xFF000000
local ballRange = 1325
local Skills, Keys, Items, Data, Jungle, Helper, MyHero, Minions, Crosshair, Orbwalker = AutoCarry.Helper:GetClasses()
local QAble, WAble, Eable, RAble = false, false, false, false
local Prodict = ProdictManager.GetInstance()
local drawDmg = true
local ProdictQ
local bestR = nil
local bestQM = nil
local from = nil
local toX, toY = 0, 0

function Plugin:__init()
  Prodict = ProdictManager.GetInstance()
  ProdictQ = Prodict:AddProdictionObject(_Q, qRange, 1100, 0.250, 80)
  Crosshair:SetSkillCrosshairRange(qRange)
  PrintChat("<font color='#FFFF33'>>> Lady of Clockwork Orianna loaded successfully</font>")
  PrintChat("<font color='#FFFF33'>>> Lady of Clockwork Orianna Version: "..version)
  if not FileExist(SCRIPT_PATH.."Common\\DrawDamageLib.lua") then
	PrintChat("<font color='#FF0033'>>>"..SCRIPT_PATH.."Common\\DrawDamageLib.lua not found! Please download DrawDamageLib!")
	drawDmg = false
  end
  _G.oldDrawCircle = rawget(_G, 'DrawCircle')
  _G.DrawCircle = DrawCircle2
end

function Plugin:OnTick()
  if ballMoving or Recalling then return end

  if Menu.M.LagFree then _G.DrawCircle = DrawCircle2
  else _G.DrawCircle = _G.oldDrawCircle end
  Checks()
  if CountEnemyHeroInRange(qRange*2) == 0 and Menu.M.tearStacker and Menu.M.tearStackerM/100 * myHero.maxMana < myHero.mana and WAble
	and not ballMoving and not Keys.AutoCarry and not Keys.MixedMode and not Keys.LaneClear and not Keys.LastHit then
	if ball == myHero then
	  CastSpell(_W)
	else
	  CastSpell(_E)
	end
  end

  CheckW()
  CheckR()
  Shield()
  RepositionBall()
end

function Plugin:OnDraw()
  if drawDmg then drawDamage() end
  if QAble and Menu.D.drawQ then
	DrawCircle(myHero.x, myHero.y, myHero.z, qRange, ballColor)
  end
  if WAble and Menu.D.drawW and ball and not ballMoving then
	DrawCircle(ball.x, ball.y, ball.z, wRange, ballColor)
  end
  if RAble and Menu.D.drawR and ball and not ballMoving then
	DrawCircle(ball.x, ball.y, ball.z, rRange, ballColor)

  end
  if Menu.D.drawB and ball and not ballMoving and ball ~= getHero and not RAble and not QAble then
	DrawCircle(ball.x, ball.y, ball.z, 100, ballColor)
  end
  if ball ~= myHero and ball and Menu.D.drawBL and not ballMoving then
	local x1, y1, onScr1 = get2DFrom3D(myHero.x, myHero.y, myHero.z)
	local x2, y2, onScr2 = get2DFrom3D(ball.x, ball.y, ball.z)
	DrawLine(x1, y1, x2, y2, 1, 0xFFFF0000)

  end
  if from and ballMoving and Menu.D.drawBL then
	local x1, y1, onScr1 = get2DFrom3D(from.x, from.y, from.z)
	local x2, y2, onScr2 = get2DFrom3D(toX, from.y, toY)
	DrawCircle(toX, from.y, toY, 100, ballColor)
	DrawLine(x1, y1, x2, y2, 10, 0x80FF0000)
  end
  if bestR and Menu.D.drawRMEC then DrawCircle(bestR.x, bestR.y, bestR.z, 300, ballColor) end
end

function getPassiveDamage(minion)
  return getDmg("P", minion, myHero)
end

function Checks()
  QAble = (myHero:CanUseSpell(_Q) == READY)
  WAble = (myHero:CanUseSpell(_W) == READY)
  EAble = (myHero:CanUseSpell(_E) == READY)
  RAble = (myHero:CanUseSpell(_R) == READY)

end

local function getHitBoxRadius(target)
  if(target == nil) then return 0 end
  return GetDistance(target, target.minBBox)
end

function getEnemiesInRange(pos, range)
local Enemies = 0
for _, Enemy in pairs(GetEnemyHeroes()) do
   Enemies = (GetDistance(Enemy, pos) <= range and not Enemy.isDead and Enemy.visible and ValidTarget(Enemy)) and Enemies + 1 or Enemies
end
return Enemies
end

function isEnemyInRange(pos, range)
  return getEnemiesInRange(pos, range) > 0
end

function CheckW()

  if Menu.W.autoW and ball and not ballMoving and ((Menu.W.minW > 0 and Menu.W.minWM/100 * myHero.maxMana < myHero.mana) or Keys.AutoCarry) then
	if isEnemyInRange(ball, wRange) then CastSpell(_W) end
  end

  if(Menu.W.minW > 0 and Menu.W.minWM/100 * myHero.maxMana < myHero.mana and ball and not ballMoving) then
	local minionCounter = 0
	for i, m in pairs(Minions.EnemyMinions.objects) do
	  local dmg = getDmg("W", m, myHero)
	  if m and m.valid and m.health < dmg and GetDistance(ball, m) < wRange then
		minionCounter = minionCounter + 1
		if minionCounter >= Menu.W.minW then
		  CastSpell(_W)
		  return
		end
	  end
	end
  end
end

function CheckR()
  if Menu.R.autoR and RAble and ball and not ballMoving then
	if getEnemiesInRange(ball, rRange) >= Menu.R.minR then
	  CastSpell(_R)
	  return
	end
	--Check if we can kill anyone with our R in the current place
	if Menu.R.useUltCombo then
	  for i, enemy in ipairs(GetEnemyHeroes()) do
		if enemy and not enemy.dead and GetDistance(enemy, ball) < rRange and enemy.health < getDmg("R", enemy, myHero)  and ValidTarget(Enemy) and enemy.visible then
		  CastSpell(_R)
		end
	  end
	end

  end
end

function checkRLocations()
  if Menu.R.autoR and RAble and ball and not ballMoving then
	for i, e in ipairs(GetEnemyHeroes()) do
	  bestR = GetAoESpellPosition(rWidth, e, 0.5)
	  if bestR then
		if getEnemiesInRange(bestR, rRange) >= Menu.R.minR and GetDistance(bestR, myHero) < qRange then
		  CastSpell(_Q, bestR.x, bestR.z)
		  return
		else
		  bestR = nil
		end
	  end
	end
  end
end

function RepositionBall()
  checkRLocations()
  if Crosshair:GetTarget() and (Keys.AutoCarry or (Keys.MixedMode and Menu.Q.minQM/100 * myHero.maxMana < myHero.mana) or (Menu.harrass and Menu.harrassM/100 * myHero.maxMana < myHero.mana)) then
	doAttack()
  end
  if Keys.LaneClear then
	doLaneClear()
  end
end

function Shield()

  if Menu.E.autoE and ball and not ballMoving then
	if ball ~= myHero then
	  for i, enemy in pairs(GetEnemyHeroes()) do
		if enemy and not enemy.dead and not myHero.dead then
		  if checkhitlinepass(ball, myHero, 30, eRange, enemy, GetDistance(enemy, enemy.minBBox)/2) then
			CastSpell(_E, myHero)
			return
		  end
		end
	  end
	  for i, ally in pairs(GetAllyHeroes()) do
		for i, enemy in pairs(GetEnemyHeroes()) do
		  if enemy and not enemy.dead and ally and not ally.dead and GetDistance(ball, ally) < eRange then
			if checkhitlinepass(ball, ally, 30, eRange, enemy, GetDistance(enemy, enemy.minBBox)/2) then
			  CastSpell(_E, ally)
			  return
			end
		  end
		end
	  end
	end
  end

  if(Menu.E.minE > 0 and Menu.E.minEM/100 * myHero.maxMana < myHero.mana and ball and myHero) then
	local deadMinions = 0
	local hitMinions = 0
	for i, m in pairs(Minions.EnemyMinions.objects) do
	  if m ~= nil and m.valid and GetDistance(myHero, ball) > GetDistance(myHero, m) and m then
		local dmg = getDmg("E", m, myHero)
		if checkhitlinepass(ball, myHero, 30, eRange, m, GetDistance(m, m.minBBox)/2) then
		  hitMinions = hitMinions + 1
		  if m.health < dmg then
			deadMinions = deadMinions + 1
		  end
		end
		if deadMinions >= Menu.E.minE or (not QAble and hitMinions > 0 and Keys.LaneClear) then
		  CastSpell(_E, myHero)
		  return
		end
	  end
	end
  end
end

function doAttack()

  local enemy = Crosshair:GetTarget()
  if not ValidTarget(enemy) or not enemy or not ball or ballMoving or enemy.dead or not enemy.visible then return end
  local r2 = GetDistance(ball, enemy)+1
  local s = (wRange * 0.5) / r2
  local dx = enemy.x - ball.x
  local dz = enemy.z - ball.z
  local x = dx * s
  local z = dz * s
  local pos, t, hitchance =  ProdictQ:GetPrediction(Crosshair:GetTarget())

  if not pos then return end

  if not checkhitlinepass(ball, Vector(pos.x+x, pos.y, pos.z+z), 30, qWidth, enemy, GetDistance(pos, enemy.minBBox)/2) then --If the Ball wont hit the enemy, then move it closer ;)
	s = (qWidth * 0.5) / r2
	dx = Crosshair:GetTarget().x - ball.x
	dz = Crosshair:GetTarget().z - ball.z
	x = dx * s
	z = dz * s
  end

  if not Menu.Q.qBehind or not EAble then
	x = 0
	z = 0
  end

  if Menu.M.longDistE and GetDistance(ball, pos) - GetDistance(myHero, pos) > 700 and EAble then
	CastSpell(_E, myHero)
	return
  end

  if pos then
	CastSpell(_Q, pos.x+x, pos.z+z)
  else
	CastSpell(_Q, enemy.x+x, enemy.z+z)
  end
end

function doLaneClear()
  local minion1 = nil
  if(Menu.Q.minQM/100 * myHero.maxMana < myHero.mana) and Menu.Q.qLaneClear and ball and not ballMoving then
	for i, m in pairs(Minions.EnemyMinions.objects) do
	  if m and GetDistance(myHero, m) < qRange then
		if m and m.valid and not m.dead and GetDistance(myHero, m) < qRange and GetDistance(ball, m) ~= 0 then minion1 = m break end
	  end
	end
	if(minion1 and minion1.valid and not minion1.dead and GetDistance(ball, minion1) ~= 0) then
	  local r2 = GetDistance(ball, minion1);
	  local s = qWidth / r2
	  local dx, dz = 0, 0;
	  if GetDistance(myHero, minion1) > GetDistance(myHero, ball) then
		dx = minion1.x - myHero.x
		dz = minion1.z - myHero.z
	  else
		s = qWidth / r2
		dx = minion1.x - myHero.x
		dz = minion1.z - myHero.z
	  end
	  local x = dx * s
	  local z = dz * s

	  if(not Menu.Q.qBehindM) then
		local mec = GetAoESpellPosition(80, minion1)
		if Menu.M.mec and mec and GetDistance(mec, myHero) < qRange then
		  CastSpell(_Q, mec.x, mec.z)
		else
		  CastSpell(_Q, minion1.x, minion1.z)
		end
	  else
		local mec = GetAoESpellPosition(wRange, minion1)
		if Menu.M.mec and mec then
		  CastSpell(_Q, mec.x+x, mec.z+z)
		else
		  CastSpell(_Q, minion1.x+x, minion1.z+z)
		end
	  end

	end
  end
end

--Ball and Buff Checking--

function CheckBall(obj)
  if obj == nil or obj.name == nil then return end
  if obj.name:find("Oriana_Ghost_mis") or obj.name:find("Oriana_Ghost_mis_protect") then ballMoving = true from = obj.pos return end
  if obj.name:find("yomu_ring_green") then ball = obj return end
  if obj.name:find("Oriana_Ghost_bind") and allyHeroes then
	for i, target in ipairs(allyHeroes) do
	  if target and GetDistance(target, obj) < 50 then
		ball = target
	  end
	end
  end
end

function RemoveBall(obj)
  if obj == nil or obj.name == nil then return end
  if obj.name:find("Oriana_Ghost_mis") or obj.name:find("Oriana_Ghost_mis_protect") then ballMoving = false return end
  if obj.name:find("yomu_ring_green") or obj.name:find("Oriana_Ghost_bind") then ball = myHero ballColor = 0xFF00FFFF return end
end

function CheckRangeColor(obj)
  if obj == nil or obj.name == nil then return end
  if obj.name == "OrianaBallIndicatorNear.troy" then ballColor = 0xFF00FFFF
  elseif obj.name == "OrianaBallIndicatorMedium.troy" then ballColor = 0xFF0000FF
  elseif obj.name == "OrianaBallIndicatorFar.troy" then ballColor = 0xFFFF0000
  end
end

function Plugin:onGainBuff(unit, buff)
  if buff.name:find("Recall") and unit.isMe then
	Recalling = true
  end
end
function Plugin:onLoseBuff(unit, buff)
  if buff.name:find("Recall") and unit.isMe then
	Recalling = false
  end
end

function Plugin:OnCreateObj(obj)
  if obj == nil or obj.name == nil then return end
  CheckBall(obj)
  CheckRangeColor(obj)
end

function Plugin:OnDeleteObj(obj)
  RemoveBall(obj)
end

function Plugin:OnSendPacket(p)
  if p.header == 0x9A and ball and Menu.R.blockR and not ballMoving then
	p.pos = 5
	spellID = p:Decode1()

	if spellID == 3 then

	  if ballMoving then
		p:Block();
		return
	  end


	  if not isEnemyInRange(ball, rRange)then
		p:Block();
	  end
	end

	if spellID == 0 then
	  toX = p:DecodeF()
	  toY = p:DecodeF()
	end

  end
end

-- Lag free circles (by barasia, vadash and viseversa)
function DrawCircleNextLvl(x, y, z, radius, width, color, chordlength)
  radius = radius or 300
  quality = math.max(8,round(180/math.deg((math.asin((chordlength/(2*radius)))))))
  quality = 2 * math.pi / quality
  radius = radius*.92
  local points = {}
  for theta = 0, 2 * math.pi + quality, quality do
	local c = WorldToScreen(D3DXVECTOR3(x + radius * math.cos(theta), y, z - radius * math.sin(theta)))
	points[#points + 1] = D3DXVECTOR2(c.x, c.y)
  end
  DrawLines2(points, width or 1, color or 4294967295)
end
function round(num)
  if num >= 0 then return math.floor(num+.5) else return math.ceil(num-.5) end
end
function DrawCircle2(x, y, z, radius, color)
  local vPos1 = Vector(x, y, z)
  local vPos2 = Vector(cameraPos.x, cameraPos.y, cameraPos.z)
  local tPos = vPos1 - (vPos1 - vPos2):normalized() * radius
  local sPos = WorldToScreen(D3DXVECTOR3(tPos.x, tPos.y, tPos.z))
  if OnScreen({ x = sPos.x, y = sPos.y }, { x = sPos.x, y = sPos.y }) then
	DrawCircleNextLvl(x, y, z, radius, 1, color, Menu.M.CL)
  end
end

AutoCarry.Plugins:RegisterBonusLastHitDamage(getPassiveDamage)

Menu = AutoCarry.Plugins:RegisterPlugin(Plugin(), "Lady of Clockwork, Orianna")
Menu:addSubMenu("--> Command: Attack", "Q")
Menu.Q:addParam("sep2", "--> Command: Attack", SCRIPT_PARAM_INFO, "")
Menu.Q:addParam("qBehind", "Ball Behind Enemies", SCRIPT_PARAM_ONOFF, true)
Menu.Q:addParam("qBehindM", "Ball Behind Minions", SCRIPT_PARAM_ONOFF, true)
Menu.Q:addParam("qLaneClear", "Use Q in LaneClear", SCRIPT_PARAM_ONOFF, true)
Menu.Q:addParam("minQM", "Lane Clear Min Mana", SCRIPT_PARAM_SLICE, 40, 0, 100, 0)

Menu:addSubMenu("--> Command: Dissonance", "W")
Menu.W:addParam("autoW", "Auto Damage Enemies", SCRIPT_PARAM_ONOFF, true)
Menu.W:addParam("minW", "Min Minions", SCRIPT_PARAM_SLICE, 3, 0, 10, 0)
Menu.W:addParam("minWM", "Min Mana", SCRIPT_PARAM_SLICE, 40, 0, 100, 0)

Menu:addSubMenu("--> Command: Protect", "E")
Menu.E:addParam("autoE", "Auto Damage Enemies", SCRIPT_PARAM_ONOFF, true)
Menu.E:addParam("minE", "Min Minions", SCRIPT_PARAM_SLICE, 2, 0, 10, 0)
Menu.E:addParam("minEM", "Min Mana", SCRIPT_PARAM_SLICE, 40, 0, 100, 0)

Menu:addSubMenu("--> Command: Shockwave", "R")
Menu.R:addParam("autoR", "Automatic", SCRIPT_PARAM_ONOFF, true)
Menu.R:addParam("blockR", "Block", SCRIPT_PARAM_ONOFF, false)
Menu.R:addParam("useUltCombo", "Use ult in Combo", SCRIPT_PARAM_ONOFF, true)
Menu.R:addParam("minR", "Min Enemies", SCRIPT_PARAM_SLICE, 3, 1, 5, 0)

Menu:addSubMenu("--> Miscellaneous", "M")
Menu.M:addParam("Flipped", "Flip DrawDamage (Requires Reload)", SCRIPT_PARAM_ONOFF, true)
Menu.M:addParam("mec", "Use Minion MEC (buggy)", SCRIPT_PARAM_ONOFF, false)
Menu.M:addParam("LagFree", "Lag Free Circles", SCRIPT_PARAM_ONOFF, false)
Menu.M:addParam("CL", "Length before snapping", 4, 300, 75, 2000, 0)
Menu.M:addParam("CLinfo", "The lower your length the better system you need", 5, "")
Menu.M:addParam("tearStacker", "Tear Stacker / Fast Travel", SCRIPT_PARAM_ONOFF, false)
Menu.M:addParam("tearStackerM", "Tear Stacker Min Mana", SCRIPT_PARAM_SLICE, 60, 0, 100, 0)
Menu.M:addParam("longDistE", "Save Time using E", SCRIPT_PARAM_ONOFF, true)
Menu.M:addParam("stealJungle", "Steal Jungle", SCRIPT_PARAM_ONOFF, true)

Menu:addSubMenu("--> Drawing Options", "D")
Menu.D:addParam("drawQ", "Draw - Q Range", SCRIPT_PARAM_ONOFF, true)
Menu.D:addParam("drawW", "Draw - W Range", SCRIPT_PARAM_ONOFF, true)
Menu.D:addParam("drawR", "Draw - R Range", SCRIPT_PARAM_ONOFF, true)
Menu.D:addParam("drawBL", "Draw - Ball Line", SCRIPT_PARAM_ONOFF, true)
Menu.D:addParam("drawB", "Draw - Ball", SCRIPT_PARAM_ONOFF, true)
Menu.D:addParam("drawRMEC", "Draw - R MEC", SCRIPT_PARAM_ONOFF, true)

Menu:addParam("harrass", "Auto Harrass", SCRIPT_PARAM_ONOFF, true)
Menu:addParam("harrassM", "Min Mana Harrass", SCRIPT_PARAM_SLICE, 60, 0, 100, 0)

if FileExist(SCRIPT_PATH.."Common\\DrawDamageLib.lua") then
  setFlipped(Menu.M.Flipped)
end

--UPDATEURL=
--HASH=AFAE8044417B7680C8E15B05092334C4
